/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "ssi_datafactory.h"

#include "ssi_defines.h"

#include "ssi_functionset.h"
#include "ssi_datafactory.h"

SSI_SCRIPTDLL_API CDataFactory* CDataFactory::theFactory = SSI_NULL;

SSI_SCRIPTDLL_API SSI_INT64 Factory_RegisterData(CData* RepData){
	return CDataFactory::getInstance()->RegisterData(RepData);
}

SSI_SCRIPTDLL_API CData* Factory_MakeData(SSI_INT64 Type){
	return CDataFactory::getInstance()->MakeData(Type);
}

SSI_SCRIPTDLL_API SSI_INT64 Factory_ClearData(){
	return CDataFactory::getInstance()->ClearData();
}
SSI_SCRIPTDLL_API SSI_INT64 Factory_RemoveData(SSI_INT64 Type){
	return CDataFactory::getInstance()->RemoveData(Type);
}

SSI_SCRIPTDLL_API CData* Factory_MakeData(const char* StringType){
	return CDataFactory::getInstance()->MakeData(StringType);
}

SSI_SCRIPTDLL_API CData* Factory_DataFromString(const char* In){
	return CDataFactory::getInstance()->DataFromString(In);
}

CDataFactory::CDataFactory(void)
: TypeCtr(0)
{
	FirstReg = SSI_NULL;
	TypeCtr = RESERVED_TYPES + 1;
}

CDataFactory::~CDataFactory(void)
{
	DelTree(FirstReg);
	FirstReg = SSI_NULL;
}

CData* CDataFactory::MakeData(SSI_INT64 Type)
{
	RegNode aNode = FindNode(Type);
	if(!aNode) return SSI_NULL;
	return aNode->aData->MakeData_Internal();
}

SSI_INT64 CDataFactory::RemoveData(SSI_INT64 Type)
{
	RegNode Ret = FirstReg;
	RegNode Del;
	while(Ret->Next){
		if(Ret->Next->Type == Type){
			Del = Ret->Next;
			Ret->Next = Del->Next;
			Del->aData->UnRegister();
  		delete Del->aData->FuncSet;
		  delete Del->aData->VarSet;
			delete Del->aData;
			delete Del;
			Ret = Ret->Next;
			if(!Ret) return 1;
		}else{
			Ret = Ret->Next;
		}
	}
	return 1;
}

int CDataFactory::RegisterData(CData* RepData)
{
	if(!RepData) return -1;

	RegNode Curr;
	if(FirstReg == SSI_NULL){
		FirstReg = NewNode();
		Curr = FirstReg;
	}
	else{
		Curr = FirstReg;
		while(Curr->Next){
			// Avoid duplicate names
			//if(Curr->aData->DataName == RepData->DataName){
			//	delete RepData;
			//	return Curr->aData->GetType();
			//}
			Curr = Curr->Next;
		}

		// Avoid duplicate names
		//if(Curr->aData->DataName == RepData->DataName){
		//	delete RepData;
		//	return Curr->aData->GetType();
		//}

		Curr->Next = NewNode();
		Curr = Curr->Next;
	}

	// Initialize the Data Member Functions
	SSI_INT64 NewType = GetType();
	if(!RepData->Register(NewType)){
		delete Curr->Next;
		Curr->Next = SSI_NULL;
		return -1;
	}
	RepData->FuncSet = new CFunctionSet();
	RepData->VarSet = new VarTree();
	RepData->Type = NewType;
	if(!RepData->InitData()){
		RepData->UnRegister();
		delete RepData->FuncSet;
		delete RepData->VarSet;
		delete Curr->Next;
		Curr->Next = SSI_NULL;
		return -1;
	}

  
	Curr->aData = RepData;
	Curr->Type = RepData->Type;
	return Curr->Type;
}

RegNode CDataFactory::NewNode(void)
{
	RegNode aNode = new RegDataT;
	aNode->aData = SSI_NULL;
	aNode->Next = SSI_NULL;
	aNode->Type = 0;
	return aNode;
}

SSI_INT64 CDataFactory::GetType(void)
{
	return TypeCtr++;
}

void CDataFactory::DelTree(RegNode aNode)
{
	if(!aNode) return;
	if(aNode->Next) DelTree(aNode->Next);

  delete aNode->Next;
	if(aNode->aData){
		aNode->aData->UnRegister();
		delete aNode->aData->FuncSet;
		delete aNode->aData->VarSet;
		delete aNode->aData;
	}
	//delete aNode;
}

RegNode CDataFactory::FindNode(SSI_INT64 Type)
{
	RegNode Ret = FirstReg;
	while(Ret){
		if(Ret->Type == Type){
			return Ret;
		}else{
			Ret = Ret->Next;
		}
	}
	return SSI_NULL;
}

CData* CDataFactory::MakeData(const char* StringType)
{
	RegNode Ret = FirstReg;
	while(Ret){
		if(Ret->aData->DataName == StringType){
			return Ret->aData->MakeData_Internal();
		}else{
			Ret = Ret->Next;
		}
	}
	return SSI_NULL;

}

CData* CDataFactory::DataFromString(const char* In)
{
	RegNode Ret = FirstReg;
	String s = In;
	while(Ret){
		if(Ret->aData->DataFromString(s)){
			return Ret->aData->MakeData_Internal();
		}else{
			Ret = Ret->Next;
		}
	}
	return SSI_NULL;
}

int CDataFactory::ClearData(void)
{
  if(theFactory){
    //theFactory->DelTree(theFactory->FirstReg);
    delete theFactory;
  }
	theFactory = 0;
	return 1;
}




